﻿using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Red.Controls.DataDriven;
using Red.Controls.Shell;
using Red.Controls.ViewModels;
using Red.Core.Extensions;
using Red.Toolkit.MeshEditor.ViewModels;

namespace Red.Toolkit.MeshEditor.Controls
{
    /// <summary>
    /// Interaction logic for StructureTreeControl.xaml
    /// </summary>
    public partial class StructureTreeControl : UserControl
    {

        #region C-tor

        public StructureTreeControl()
        {
            InitializeComponent();
        }

        #endregion

        #region Public methods

        public void Refresh()
        {
            if ( _structureTree.SelectedItem != null )
            {
                _structureTree.SelectedItem.IsSelected = false;
            }
            _structureTree.Refresh().DoNotAwait();
        }

        #endregion

        #region Event handlers

        private void StructureTree_SelectedItemChanged( object sender, RoutedPropertyChangedEventArgs<object> e )
        {
            DataItem element = e.NewValue as DataItem;
            if ( element != null )
            {
                _structureStacker.Visibility = Visibility.Visible;
                InteropExtension.SetPath( _structureDataCategory, element.Path.Substring( element.Path.IndexOf( "tree" ) ) );
                // handle material case
            }
            else
            {
                _structureStacker.Visibility = Visibility.Hidden;
            }
        }


        private async void RemoveLOD_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            DataItem node = e.Parameter as DataItem;

            var result = await node.ExecuteAsync<bool>( "removeLOD" );
            if ( !result.Value )
            {
                RedMessageBox.Show( this, RedDialogType.Ok, "Removing LOD failed." );
            }
        }

        private void RemoveLOD_CanExecute( object sender, CanExecuteRoutedEventArgs e )
        {
            var toRemove = _structureTree.SelectedItem as InteropTreeItem;

            InteropTreeItem parent = _structureTree.GetParent( toRemove.NodeID );
            if ( parent != null )
            {
                e.CanExecute = parent.ChildrenCount > 1;
            }
        }

        private void AddLOD_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            DataItem node = e.Parameter as DataItem;
            if ( node == null )
            {
                return;
            }
            
            LodDescriptionViewModel lodDesc = new LodDescriptionViewModel();

            int currentLodsNum = node.Children.Count;
            AddLodDialog addLodDlg = new AddLodDialog( Window.GetWindow( this ), lodDesc );
            if ( addLodDlg.Execute_ActionMode( currentLodsNum ) )
            {
                if ( lodDesc.SelectedLod == currentLodsNum )
                {
                    lodDesc.SelectedLod = -1;
                }

                AddLod( lodDesc, node ).DoNotAwait();
            }
        }

        private void GenerateLODs_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            DataItem node = e.Parameter as DataItem;
            if ( node == null )
            {
                return;
            }

            LodsGeneratorDialog generatorDlg = new LodsGeneratorDialog( Window.GetWindow( this ) );
            if ( generatorDlg.Execute() )
            {
                GenerateLods( generatorDlg.LodDescriptions, node ).DoNotAwait();
            }
        }

        private void AddCollision_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            if ( _structureTree.SelectedItem != null )
            {
                _structureTree.SelectedItem.Execute( "addCollision", e.Parameter );
            }
        }

        private void RemoveCollision_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            if ( _structureTree.SelectedItem != null )
            {
                _structureTree.SelectedItem.Execute( "removeCollision" );
            }
        }
        #endregion

        #region Private methods
        private async Task AddLod( LodDescriptionViewModel lodDesc, DataItem node )
        {
            Mouse.OverrideCursor = Cursors.Wait;
            var result = await node.ExecuteAsync<bool>( "addLOD", lodDesc.SelectedLod, lodDesc.ReductionFactor, lodDesc.Distance, lodDesc.ChunksLimit );
            Mouse.OverrideCursor = null;

            if ( !result.Value )
            {
                RedMessageBox.Show( this, RedDialogType.Ok, "Adding LOD failed." );
            }
        }

        private async Task GenerateLods( List<LodDescriptionViewModel> lodDescriptions, DataItem node )
        {
            Mouse.OverrideCursor = Cursors.Wait;
            var result = await node.ExecuteAsync<bool>( "removeLODs" );
            bool created = true;

            if ( result.Value )
            {
                foreach ( var lodDesc in lodDescriptions )
                {
                    var lodCreated = await node.ExecuteAsync<bool>( "addLOD", lodDesc.SelectedLod, lodDesc.ReductionFactor, lodDesc.Distance, lodDesc.ChunksLimit );
                    if ( !lodCreated.Value )
                    {
                        created = false;
                        break;
                    }
                }
            }

            Mouse.OverrideCursor = null;

            if ( !created )
            {
                RedMessageBox.Show( this, RedDialogType.Ok, "Generating LODs failed." );
            }
        }

        #endregion Private methods
    }
}
